package com.wzw.basics.reflection.example;

import java.lang.reflect.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.SimpleTimeZone;

/**
 * class 类名<泛型变量1,泛型变量2,泛型变量3 extends 上边界1,泛型变量4 extends 上边界类型1 & 上边界类型2 & 上边界类型3>
 * 泛型变量需要在类名后面的括号中定义
 * 每个类中可以定义多个泛型变量，多个泛型变量之间用逗号隔开
 * 泛型变量可以通过extends关键字指定上边界，上边界可以对泛型变量起到了限定的作用
 * 上边界可以指定0到多个，多个之间需要用&符号隔开，如果不指定上边界，默认上边界为Object类型
 *
 * @author Wangzhiwen
 */
public class Demo<T1, T2 extends Number, T3 extends Demo1 & Demo2> {

    public void ignored() {

    }

    public static <T, K extends Number, V extends Demo1 & Demo2> T genericMethodExample(T t, K k, V v, String normal) {
        System.out.println("泛型方法输出: " + t + k + v + normal);
        return t;
    }

    public static void m2(String name) {
        System.out.println(name);
    }

    public static void genericClass() {
        /*
         * Class.class
         * Object.getClass() 这里对象带有具体的泛型类型而不是占位符
         * Class<?> demoClass = demo.getClass(); ? 通配符表示不会有警告
         * 本质上都是返回Class对象，Class<T>是泛型类。不会对getTypeParameters方法产生影响，都是返回占位符名称
         */
        // Demo<String, Integer, Demo3> demo = new Demo<>();
        // Class<? extends Demo> aClass1 = demo.getClass();
        Class<?> demoClass = Demo.class;
        // 获取当前类泛型
        TypeVariable<? extends Class<?>>[] typeParameters = demoClass.getTypeParameters();
        for (TypeVariable<? extends Class<?>> typeParameter : typeParameters) {
            String name = typeParameter.getName();
            System.out.println("泛型变量名称: " + name);
            Class<?> genericDeclaration = typeParameter.getGenericDeclaration();
            System.out.println("泛型变量在哪个类中声明: " + genericDeclaration);
            Type[] bounds = typeParameter.getBounds();
            for (Type bound : bounds) {
                // 这里bound就是Class类型
                Class<?> aClass = (Class<?>) bound;
                System.out.println("泛型边界名称: " + aClass.getSimpleName());
                System.out.println("泛型边界名称: " + bound.getTypeName());
            }
            AnnotatedType[] annotatedBounds = typeParameter.getAnnotatedBounds();
            System.out.println();
        }
        // 获取父类泛型
        Type[] genericInterfaces = demoClass.getGenericInterfaces();
    }

    public static void genericMethod() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<?> demoClass = Demo.class;
        Method[] declaredMethods = demoClass.getDeclaredMethods();
        Method genericMethod = Arrays.stream(declaredMethods).filter(method -> method.getName().equals("genericMethodExample")).findFirst().orElseThrow(NoSuchFieldError::new);
        // 获取方法的全部的入参类型，如果是泛型则返回泛型类TypeVariable，不是就返回Class
        Type[] genericParameterTypes = genericMethod.getGenericParameterTypes();
        for (Type type : genericParameterTypes) {
            // 泛型就是泛型变量类型
            if (type instanceof TypeVariable) {
                TypeVariable<?> typeVariable = (TypeVariable<?>) type;
                System.out.println("变量类型名称: " + typeVariable.getTypeName());
                System.out.println("变量名称: " + typeVariable.getName());
                System.out.println("这个变量在哪声明的: " + typeVariable.getGenericDeclaration());
                Type[] bounds = typeVariable.getBounds();
                System.out.println("这个变量上边界数量: " + bounds.length);
                System.out.println("这个变量上边界清单: ");
                for (Type bound : bounds) {
                    System.out.println(bound.getTypeName());
                }
            }
            // 非泛型就是Class类型
            if (type instanceof Class) {
                Class<?> clazz = (Class<?>) type;
                System.out.println("变量类型名称: " + clazz.getName());
            }
        }

        // 只获取该声明方法的泛型占位符：T K V 。如果不是泛型参数，返回空
        TypeVariable<Method>[] typeParameters = genericMethod.getTypeParameters();

        // 获取方法返回的参数类型，如果不是泛型则返回Class，是泛型返回泛型变量
        Type genericReturnType = genericMethod.getGenericReturnType();

        // 执行方法
        Object instance = demoClass.getDeclaredConstructor().newInstance();
        Object invoke = genericMethod.invoke(instance, "arg1", 100, new Demo3(), "normal");
        Type returnType = genericMethod.getGenericReturnType();
        if (returnType instanceof TypeVariable) {
            // 返回值时泛型变量
            TypeVariable<?> typeVariable = (TypeVariable<?>) returnType;
        }
        if (returnType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) returnType;
        }
        if (returnType instanceof Class) {
            Class<?> type = (Class<?>) returnType;
        }
        System.out.println(invoke);
    }

    public static void useParameterizedType() throws NoSuchMethodException {
        // 泛型类方法
        {
            Class<?> aClass = Demo4.C1.class;
            Method method = aClass.getMethod("m1", List.class, Map.class);
            Type[] genericParameterTypes = method.getGenericParameterTypes();
            for (Type type : genericParameterTypes) {
                if (type instanceof ParameterizedType) {
                    ParameterizedType parameterizedType = (ParameterizedType) type;
                    Type rawType = parameterizedType.getRawType();
                    System.out.println("rawType : " + rawType);
                    Type ownerType = parameterizedType.getOwnerType();
                    System.out.println("ownerType : " + ownerType);
                    // [0] -> T [1] -> [String,Long]
                    Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                    for (Type argument : actualTypeArguments) {
                        if (argument instanceof TypeVariable) {
                            TypeVariable<?> variable = (TypeVariable<?>) argument;
                            Type[] bounds = variable.getBounds();
                        }
                        if (argument instanceof Class) {
                            Class<?> clazz = (Class<?>) argument;
                            System.out.println(clazz.getName());
                        }
                    }
                }
            }
        }

        // 泛型类 指定了父类Demo5的具体类型
        {
            Demo6 demo6 = new Demo6();
            Class<? extends Demo6> demo6Class = demo6.getClass();
            // 父类泛型 此方法常用于获取泛型中套取泛型的具体类型，如：Object<T> T 是一个泛型套泛型 <List<T>>
            Type genericSuperclass = demo6Class.getGenericSuperclass();
            // 泛型类型用ParameterizedType接口表示，输出看一下是不是这个接口类型的
            System.out.println(genericSuperclass.getClass());
            if (genericSuperclass instanceof ParameterizedType) {
                ParameterizedType superclass = (ParameterizedType) genericSuperclass;
                // 获取具体类型
                Type[] arguments = superclass.getActualTypeArguments();
                for (Type type : arguments) {
                    System.out.println("actualType : " + type.getTypeName());
                }
            }
        }

    }

    public static void useWildcardType() {

    }

    public static void useGenericArrayType() throws NoSuchFieldException {
        Class<Demo8> aClass = Demo8.class;
        Field field = aClass.getDeclaredField("array");
        // 泛型数组类型就是 GenericArrayType
        Type type = field.getGenericType();
        if (type instanceof GenericArrayType) {
            GenericArrayType genericArrayType = (GenericArrayType) type;
            System.out.println(genericArrayType.getClass());
            System.out.println(genericArrayType.getTypeName());
            // 获取数组中具体的类型 -> List<String> -> parameterizedType
            Type componentType = genericArrayType.getGenericComponentType();
            if (componentType instanceof ParameterizedType) {
                ParameterizedType parameterizedType = (ParameterizedType) componentType;
                Type[] arguments = parameterizedType.getActualTypeArguments();
                // 实际类型 -> String
                Type argument = arguments[0];
                Class<?> clazzType = (Class<?>) argument;
                System.out.println(clazzType.getName());
            }
        }
    }

    public static void resolveIntricacyGeneric() throws NoSuchFieldException {
        Class<?> demo9Class = Demo9.class;
        Field field = demo9Class.getDeclaredField("map");
        Type fieldGenericType = field.getGenericType();
        // 泛型数组类型
        GenericArrayType genericArrayType = (GenericArrayType) fieldGenericType;
        Type componentType = genericArrayType.getGenericComponentType();
        // 组件类型还是泛型数组
        GenericArrayType arrayType = (GenericArrayType) componentType;
        Type type = arrayType.getGenericComponentType();
        // 实际类型是泛型类
        ParameterizedType parameterizedType = (ParameterizedType) type;
        // 泛型类里的实际类型分为 String 和 通配符类型
        Type[] arguments = parameterizedType.getActualTypeArguments();
        for (Type argument : arguments) {
            if (argument instanceof Class) {
                Class<?> aClass = (Class<?>) argument;
            }
            if (argument instanceof WildcardType) {
                WildcardType wildcardType = (WildcardType) argument;
                Type[] upperBounds = wildcardType.getUpperBounds();
                // 通配符的上边界又是泛型类
                for (Type upperBound : upperBounds) {
                    if (upperBound instanceof ParameterizedType) {
                        ParameterizedType bound = (ParameterizedType) upperBound;
                        // 泛型类实际参数类型是 泛型变量
                        Type[] types = bound.getActualTypeArguments();
                        for (Type t : types) {
                            if (t instanceof TypeVariable){
                                TypeVariable<?> typeVariable = (TypeVariable<?>) t;
                            }
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        // 获取泛型变量 TypeVariable 类型
        genericClass();
        genericMethod();

        System.out.println();

        // 获取泛型类型 ParameterizedType
        useParameterizedType();

        // 获取泛型通配符 WildcardType
        useWildcardType();
        // 获取泛型数组 GenericArrayType
        useGenericArrayType();
        // 负杂对象解析
        resolveIntricacyGeneric();
    }

}
